package service

import (
	"context"
	"fmt"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"

	"goldtree/internal/dao"
	"goldtree/internal/entity"
)

// StockService 股票服务
type StockService struct{}

var Stock = StockService{}

// CreateStockReq 创建股票请求
type CreateStockReq struct {
	Code        string  `json:"code" v:"required|length:6,10#股票代码不能为空|股票代码长度为6-10位"`
	Name        string  `json:"name" v:"required|length:1,100#股票名称不能为空|股票名称长度不能超过100位"`
	Market      string  `json:"market" v:"required|in:SH,SZ,BJ#市场代码不能为空|市场代码必须为SH,SZ,BJ之一"`
	Industry    string  `json:"industry"`
	Sector      string  `json:"sector"`
	MarketCap   float64 `json:"market_cap"`
	PeRatio     float64 `json:"pe_ratio"`
	PbRatio     float64 `json:"pb_ratio"`
	ListingDate string  `json:"listing_date"`
}

// UpdateStockReq 更新股票请求
type UpdateStockReq struct {
	Id          int     `json:"id" v:"required|min:1#ID不能为空|ID必须大于0"`
	Name        string  `json:"name" v:"required|length:1,100#股票名称不能为空|股票名称长度不能超过100位"`
	Market      string  `json:"market" v:"required|in:SH,SZ,BJ#市场代码不能为空|市场代码必须为SH,SZ,BJ之一"`
	Industry    string  `json:"industry"`
	Sector      string  `json:"sector"`
	MarketCap   float64 `json:"market_cap"`
	PeRatio     float64 `json:"pe_ratio"`
	PbRatio     float64 `json:"pb_ratio"`
	ListingDate string  `json:"listing_date"`
	IsActive    *bool   `json:"is_active"`
}

// GetStockListReq 获取股票列表请求
type GetStockListReq struct {
	Page       int     `json:"page" v:"min:1#页码必须大于0"`
	Limit      int     `json:"limit" v:"min:1|max:100#每页数量必须大于0|每页数量不能超过100"`
	Keyword    string  `json:"keyword"`
	Market     string  `json:"market"`
	Industry   string  `json:"industry"`
	Sector     string  `json:"sector"`
	IsActive   *bool   `json:"is_active"`
	MinMktCap  float64 `json:"min_market_cap"` // 最小市值
	MaxMktCap  float64 `json:"max_market_cap"` // 最大市值
	MinPeRatio float64 `json:"min_pe_ratio"`   // 最小市盈率
	MaxPeRatio float64 `json:"max_pe_ratio"`   // 最大市盈率
	SortBy     string  `json:"sort_by"`        // 排序字段
	SortOrder  string  `json:"sort_order"`     // 排序方向 asc/desc
}

// StockListRes 股票列表响应
type StockListRes struct {
	List  []*entity.Stock `json:"list"`
	Total int             `json:"total"`
	Page  int             `json:"page"`
	Limit int             `json:"limit"`
}

// StockImportReq 股票导入请求
type StockImportReq struct {
	Stocks       []*CreateStockReq `json:"stocks" v:"required#股票列表不能为空"`
	SkipExists   bool              `json:"skip_exists"`   // 是否跳过已存在的股票
	UpdateExists bool              `json:"update_exists"` // 是否更新已存在的股票
}

// StockImportRes 股票导入响应
type StockImportRes struct {
	TotalCount   int      `json:"total_count"`   // 总数量
	SuccessCount int      `json:"success_count"` // 成功数量
	FailedCount  int      `json:"failed_count"`  // 失败数量
	SkippedCount int      `json:"skipped_count"` // 跳过数量
	UpdatedCount int      `json:"updated_count"` // 更新数量
	Errors       []string `json:"errors"`        // 错误信息
}

// StockStatisticsRes 股票统计响应
type StockStatisticsRes struct {
	TotalCount      int             `json:"total_count"`       // 总股票数
	ActiveCount     int             `json:"active_count"`      // 有效股票数
	InactiveCount   int             `json:"inactive_count"`    // 无效股票数
	MarketStats     map[string]int  `json:"market_stats"`      // 市场统计
	IndustryStats   map[string]int  `json:"industry_stats"`    // 行业统计
	MarketCapRanges map[string]int  `json:"market_cap_ranges"` // 市值区间统计
	TopByMarketCap  []*entity.Stock `json:"top_by_market_cap"` // 市值前10
}

// StockValidationRes 股票验证响应
type StockValidationRes struct {
	IsValid bool     `json:"is_valid"`
	Errors  []string `json:"errors"`
}

// Create 创建股票
func (s *StockService) Create(ctx context.Context, req *CreateStockReq) (*entity.Stock, error) {
	// 验证股票代码是否已存在
	exists, err := dao.Stock.IsCodeExists(ctx, req.Code)
	if err != nil {
		return nil, gerror.Wrap(err, "检查股票代码失败")
	}
	if exists {
		return nil, gerror.New("股票代码已存在")
	}

	// 构建股票实体
	stock := &entity.Stock{
		Code:      req.Code,
		Name:      req.Name,
		Market:    req.Market,
		Industry:  req.Industry,
		Sector:    req.Sector,
		MarketCap: req.MarketCap,
		PeRatio:   req.PeRatio,
		PbRatio:   req.PbRatio,
		IsActive:  true,
	}

	// 处理上市日期
	if req.ListingDate != "" {
		// 这里可以添加日期格式验证和转换逻辑
		// stock.ListingDate = ...
	}

	// 插入数据库
	id, err := dao.Stock.Insert(ctx, stock)
	if err != nil {
		return nil, gerror.Wrap(err, "创建股票失败")
	}

	// 返回创建的股票信息
	stock.Id = int(id)
	g.Log().Info(ctx, "创建股票成功", "code", req.Code, "name", req.Name)
	return stock, nil
}

// Update 更新股票
func (s *StockService) Update(ctx context.Context, req *UpdateStockReq) error {
	// 检查股票是否存在
	existingStock, err := dao.Stock.GetById(ctx, req.Id)
	if err != nil {
		return gerror.Wrap(err, "获取股票信息失败")
	}
	if existingStock == nil {
		return gerror.New("股票不存在")
	}

	// 构建更新数据
	updateData := &entity.Stock{
		Name:      req.Name,
		Market:    req.Market,
		Industry:  req.Industry,
		Sector:    req.Sector,
		MarketCap: req.MarketCap,
		PeRatio:   req.PeRatio,
		PbRatio:   req.PbRatio,
	}

	if req.IsActive != nil {
		updateData.IsActive = *req.IsActive
	}

	// 处理上市日期
	if req.ListingDate != "" {
		// 这里可以添加日期格式验证和转换逻辑
		// updateData.ListingDate = ...
	}

	// 更新数据库
	err = dao.Stock.Update(ctx, req.Id, updateData)
	if err != nil {
		return gerror.Wrap(err, "更新股票失败")
	}

	g.Log().Info(ctx, "更新股票成功", "id", req.Id, "code", existingStock.Code)
	return nil
}

// Delete 删除股票
func (s *StockService) Delete(ctx context.Context, id int) error {
	// 检查股票是否存在
	stock, err := dao.Stock.GetById(ctx, id)
	if err != nil {
		return gerror.Wrap(err, "获取股票信息失败")
	}
	if stock == nil {
		return gerror.New("股票不存在")
	}

	// 删除股票
	err = dao.Stock.Delete(ctx, id)
	if err != nil {
		return gerror.Wrap(err, "删除股票失败")
	}

	g.Log().Info(ctx, "删除股票成功", "id", id, "code", stock.Code)
	return nil
}

// GetById 根据ID获取股票
func (s *StockService) GetById(ctx context.Context, id int) (*entity.Stock, error) {
	stock, err := dao.Stock.GetById(ctx, id)
	if err != nil {
		return nil, gerror.Wrap(err, "获取股票信息失败")
	}
	return stock, nil
}

// GetByCode 根据代码获取股票
func (s *StockService) GetByCode(ctx context.Context, code string) (*entity.Stock, error) {
	stock, err := dao.Stock.GetByCode(ctx, code)
	if err != nil {
		return nil, gerror.Wrap(err, "获取股票信息失败")
	}
	return stock, nil
}

// GetList 获取股票列表
func (s *StockService) GetList(ctx context.Context, req *GetStockListReq) (*StockListRes, error) {
	// 设置默认值
	if req.Page == 0 {
		req.Page = 1
	}
	if req.Limit == 0 {
		req.Limit = 20
	}
	if req.SortBy == "" {
		req.SortBy = "id"
	}
	if req.SortOrder == "" {
		req.SortOrder = "desc"
	}

	var stocks []*entity.Stock
	var total int
	var err error

	// 构建查询条件
	conditions := make([]interface{}, 0)
	whereClauses := make([]string, 0)

	// 关键字搜索
	if req.Keyword != "" {
		whereClauses = append(whereClauses, "(code LIKE ? OR name LIKE ?)")
		conditions = append(conditions, "%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}

	// 市场筛选
	if req.Market != "" {
		whereClauses = append(whereClauses, "market = ?")
		conditions = append(conditions, req.Market)
	}

	// 行业筛选
	if req.Industry != "" {
		whereClauses = append(whereClauses, "industry = ?")
		conditions = append(conditions, req.Industry)
	}

	// 板块筛选
	if req.Sector != "" {
		whereClauses = append(whereClauses, "sector = ?")
		conditions = append(conditions, req.Sector)
	}

	// 状态筛选
	if req.IsActive != nil {
		whereClauses = append(whereClauses, "is_active = ?")
		conditions = append(conditions, *req.IsActive)
	}

	// 市值范围筛选
	if req.MinMktCap > 0 {
		whereClauses = append(whereClauses, "market_cap >= ?")
		conditions = append(conditions, req.MinMktCap)
	}
	if req.MaxMktCap > 0 {
		whereClauses = append(whereClauses, "market_cap <= ?")
		conditions = append(conditions, req.MaxMktCap)
	}

	// 市盈率范围筛选
	if req.MinPeRatio > 0 {
		whereClauses = append(whereClauses, "pe_ratio >= ?")
		conditions = append(conditions, req.MinPeRatio)
	}
	if req.MaxPeRatio > 0 {
		whereClauses = append(whereClauses, "pe_ratio <= ?")
		conditions = append(conditions, req.MaxPeRatio)
	}

	// 构建最终的查询条件
	var finalConditions []interface{}
	if len(whereClauses) > 0 {
		where := fmt.Sprintf("%s", whereClauses[0])
		for i := 1; i < len(whereClauses); i++ {
			where += " AND " + whereClauses[i]
		}
		finalConditions = append(finalConditions, where)
		finalConditions = append(finalConditions, conditions...)
	}

	// 获取列表
	stocks, err = dao.Stock.GetListWithSort(ctx, req.Page, req.Limit, req.SortBy, req.SortOrder, finalConditions...)
	if err != nil {
		return nil, gerror.Wrap(err, "获取股票列表失败")
	}

	// 获取总数
	total, err = dao.Stock.GetCount(ctx, finalConditions...)
	if err != nil {
		return nil, gerror.Wrap(err, "获取股票总数失败")
	}

	return &StockListRes{
		List:  stocks,
		Total: total,
		Page:  req.Page,
		Limit: req.Limit,
	}, nil
}

// BatchCreate 批量创建股票
func (s *StockService) BatchCreate(ctx context.Context, stocks []*CreateStockReq) error {
	if len(stocks) == 0 {
		return gerror.New("股票列表不能为空")
	}

	// 转换为实体对象
	stockEntities := make([]*entity.Stock, 0, len(stocks))
	for _, stock := range stocks {
		// 验证股票代码是否已存在
		exists, err := dao.Stock.IsCodeExists(ctx, stock.Code)
		if err != nil {
			return gerror.Wrapf(err, "检查股票代码失败: %s", stock.Code)
		}
		if exists {
			g.Log().Warning(ctx, "股票代码已存在，跳过", "code", stock.Code)
			continue
		}

		entity := &entity.Stock{
			Code:      stock.Code,
			Name:      stock.Name,
			Market:    stock.Market,
			Industry:  stock.Industry,
			Sector:    stock.Sector,
			MarketCap: stock.MarketCap,
			PeRatio:   stock.PeRatio,
			PbRatio:   stock.PbRatio,
			IsActive:  true,
		}
		stockEntities = append(stockEntities, entity)
	}

	if len(stockEntities) == 0 {
		return gerror.New("没有有效的股票数据需要插入")
	}

	// 批量插入
	err := dao.Stock.BatchInsert(ctx, stockEntities)
	if err != nil {
		return gerror.Wrap(err, "批量创建股票失败")
	}

	g.Log().Info(ctx, "批量创建股票成功", "count", len(stockEntities))
	return nil
}

// GetIndustryList 获取行业列表
func (s *StockService) GetIndustryList(ctx context.Context) ([]string, error) {
	industries, err := dao.Stock.GetIndustryList(ctx)
	if err != nil {
		return nil, gerror.Wrap(err, "获取行业列表失败")
	}
	return industries, nil
}

// GetMarketList 获取市场列表
func (s *StockService) GetMarketList(ctx context.Context) ([]string, error) {
	markets, err := dao.Stock.GetMarketList(ctx)
	if err != nil {
		return nil, gerror.Wrap(err, "获取市场列表失败")
	}
	return markets, nil
}

// ImportStocks 导入股票数据
func (s *StockService) ImportStocks(ctx context.Context, req *StockImportReq) (*StockImportRes, error) {
	result := &StockImportRes{
		TotalCount: len(req.Stocks),
		Errors:     make([]string, 0),
	}

	for _, stockReq := range req.Stocks {
		// 检查股票是否已存在
		exists, err := dao.Stock.IsCodeExists(ctx, stockReq.Code)
		if err != nil {
			result.Errors = append(result.Errors, fmt.Sprintf("检查股票代码%s失败: %v", stockReq.Code, err))
			result.FailedCount++
			continue
		}

		if exists {
			if req.SkipExists {
				result.SkippedCount++
				continue
			} else if req.UpdateExists {
				// 更新已存在的股票
				existingStock, err := dao.Stock.GetByCode(ctx, stockReq.Code)
				if err != nil {
					result.Errors = append(result.Errors, fmt.Sprintf("获取股票%s信息失败: %v", stockReq.Code, err))
					result.FailedCount++
					continue
				}

				updateReq := &UpdateStockReq{
					Id:          existingStock.Id,
					Name:        stockReq.Name,
					Market:      stockReq.Market,
					Industry:    stockReq.Industry,
					Sector:      stockReq.Sector,
					MarketCap:   stockReq.MarketCap,
					PeRatio:     stockReq.PeRatio,
					PbRatio:     stockReq.PbRatio,
					ListingDate: stockReq.ListingDate,
				}
				err = s.Update(ctx, updateReq)
				if err != nil {
					result.Errors = append(result.Errors, fmt.Sprintf("更新股票%s失败: %v", stockReq.Code, err))
					result.FailedCount++
				} else {
					result.UpdatedCount++
				}
			} else {
				result.Errors = append(result.Errors, fmt.Sprintf("股票代码%s已存在", stockReq.Code))
				result.FailedCount++
			}
			continue
		}

		// 创建新股票
		_, err = s.Create(ctx, stockReq)
		if err != nil {
			result.Errors = append(result.Errors, fmt.Sprintf("创建股票%s失败: %v", stockReq.Code, err))
			result.FailedCount++
		} else {
			result.SuccessCount++
		}
	}

	g.Log().Info(ctx, "股票导入完成", "total", result.TotalCount, "success", result.SuccessCount,
		"failed", result.FailedCount, "skipped", result.SkippedCount, "updated", result.UpdatedCount)

	return result, nil
}

// GetStatistics 获取股票统计信息
func (s *StockService) GetStatistics(ctx context.Context) (*StockStatisticsRes, error) {
	result := &StockStatisticsRes{
		MarketStats:     make(map[string]int),
		IndustryStats:   make(map[string]int),
		MarketCapRanges: make(map[string]int),
	}

	// 获取总数量
	totalCount, err := dao.Stock.GetCount(ctx)
	if err != nil {
		return nil, gerror.Wrap(err, "获取股票总数失败")
	}
	result.TotalCount = totalCount

	// 获取有效股票数量
	activeCount, err := dao.Stock.GetCount(ctx, "is_active = ?", true)
	if err != nil {
		return nil, gerror.Wrap(err, "获取有效股票数失败")
	}
	result.ActiveCount = activeCount
	result.InactiveCount = totalCount - activeCount

	// 获取市场统计
	marketStats, err := dao.Stock.GetMarketStatistics(ctx)
	if err != nil {
		return nil, gerror.Wrap(err, "获取市场统计失败")
	}
	result.MarketStats = marketStats

	// 获取行业统计
	industryStats, err := dao.Stock.GetIndustryStatistics(ctx)
	if err != nil {
		return nil, gerror.Wrap(err, "获取行业统计失败")
	}
	result.IndustryStats = industryStats

	// 获取市值区间统计
	marketCapRanges, err := dao.Stock.GetMarketCapRanges(ctx)
	if err != nil {
		return nil, gerror.Wrap(err, "获取市值区间统计失败")
	}
	result.MarketCapRanges = marketCapRanges

	// 获取市值前10股票
	topStocks, err := dao.Stock.GetTopByMarketCap(ctx, 10)
	if err != nil {
		return nil, gerror.Wrap(err, "获取市值前10股票失败")
	}
	result.TopByMarketCap = topStocks

	return result, nil
}

// ValidateStock 验证股票数据
func (s *StockService) ValidateStock(ctx context.Context, req *CreateStockReq) (*StockValidationRes, error) {
	result := &StockValidationRes{
		IsValid: true,
		Errors:  make([]string, 0),
	}

	// 验证股票代码格式
	if !s.isValidStockCode(req.Code, req.Market) {
		result.IsValid = false
		result.Errors = append(result.Errors, "股票代码格式不正确")
	}

	// 检查股票代码是否已存在
	exists, err := dao.Stock.IsCodeExists(ctx, req.Code)
	if err != nil {
		result.IsValid = false
		result.Errors = append(result.Errors, "检查股票代码失败")
	} else if exists {
		result.IsValid = false
		result.Errors = append(result.Errors, "股票代码已存在")
	}

	// 验证数值范围
	if req.MarketCap < 0 {
		result.IsValid = false
		result.Errors = append(result.Errors, "市值不能为负数")
	}
	if req.PeRatio < 0 {
		result.IsValid = false
		result.Errors = append(result.Errors, "市盈率不能为负数")
	}
	if req.PbRatio < 0 {
		result.IsValid = false
		result.Errors = append(result.Errors, "市净率不能为负数")
	}

	return result, nil
}

// isValidStockCode 验证股票代码格式
func (s *StockService) isValidStockCode(code, market string) bool {
	if len(code) != 6 {
		return false
	}

	// 验证数字格式
	for _, char := range code {
		if char < '0' || char > '9' {
			return false
		}
	}

	// 验证市场前缀
	switch market {
	case "SH":
		// 上海交易所: 60xxxx, 688xxx, 689xxx
		return code[:2] == "60" || code[:3] == "688" || code[:3] == "689"
	case "SZ":
		// 深圳交易所: 00xxxx, 002xxx, 003xxx, 300xxx
		return code[:2] == "00" || code[:3] == "002" || code[:3] == "003" || code[:3] == "300"
	case "BJ":
		// 北京交易所: 8xxxxx, 4xxxxx
		return code[:1] == "8" || code[:1] == "4"
	default:
		return false
	}
}

// SyncMarketData 同步市场数据（留给后续实现）
func (s *StockService) SyncMarketData(ctx context.Context) error {
	// TODO: 实现从第三方数据源同步市场数据
	g.Log().Info(ctx, "市场数据同步功能暂未实现")
	return nil
}

// GetSectorList 获取板块列表
func (s *StockService) GetSectorList(ctx context.Context) ([]string, error) {
	sectors, err := dao.Stock.GetSectorList(ctx)
	if err != nil {
		return nil, gerror.Wrap(err, "获取板块列表失败")
	}
	return sectors, nil
}

// BulkUpdateStatus 批量更新股票状态
func (s *StockService) BulkUpdateStatus(ctx context.Context, codes []string, isActive bool) error {
	if len(codes) == 0 {
		return gerror.New("股票代码列表不能为空")
	}

	err := dao.Stock.BulkUpdateStatus(ctx, codes, isActive)
	if err != nil {
		return gerror.Wrap(err, "批量更新股票状态失败")
	}

	status := "禁用"
	if isActive {
		status = "启用"
	}
	g.Log().Info(ctx, "批量更新股票状态成功", "count", len(codes), "status", status)
	return nil
}
